<script lang="tsx">
  import {
    defineComponent,
    nextTick,
    onMounted,
    reactive,
    computed,
    ref,
    unref,
    VNode,
    onUnmounted,
  } from 'vue'
  import { Menu, Divider } from 'ant-design-vue'
  import { props } from './props'
  import { Props, ContextMenuItem } from './types'

  export default defineComponent({
    name: 'ContextMenu',
    props,
    setup(props) {
      const selectedKeys = ref([])
      const prefixCls = 'content-menu'
      const wrapRef = ref<HTMLDivElement | null>(null)
      const state = reactive({
        show: false,
      })
      onMounted(() => {
        nextTick(() => {
          state.show = true
        })
      })
      onUnmounted(() => {
        const el = unref(wrapRef)
        el && document.body.removeChild(el)
      })
      const getStyle = computed(() => {
        const { axis, items, styles, width } = props
        const { x, y } = axis || { x: 0, y: 0 }
        const menuHeight = (items || []).length * 40
        const menuWidth = width
        const body = document.body
        return {
          ...styles,
          width: `${width}px`,
          left: (body.clientWidth < x + menuWidth ? x - menuWidth : x) + 'px',
          top: (body.clientHeight < y + menuHeight ? y - menuHeight : y) + 'px',
        }
      })
      function handleAction(item: ContextMenuItem, e: MouseEvent) {
        // e.stopPropagation();
        const { handler, disabled, children } = item
        if (disabled || children) {
          e.preventDefault()
          e.stopPropagation()
          return
        }
        state.show = true
        handler && handler(item)
      }
      function renderContent(item: ContextMenuItem) {
        const { icon, label } = item

        const { showIcon } = props
        return (
          <span style="display: inline-block; width: 100%;" onClick={handleAction.bind(null, item)}>
            {showIcon && icon && <div class="mr-2" />}
            <span>{label}</span>
          </span>
        )
      }
      function renderMenuItem(items: ContextMenuItem[]) {
        return items.map((item, index) => {
          const { disabled, label, children, divider = true } = item

          const DividerComp = divider ? <Divider key={`d-${index}`} /> : null
          if (!children || children.length === 0) {
            return [
              <Menu.Item disabled={disabled} key={label}>
                {renderContent(item)}
              </Menu.Item>,
              DividerComp,
            ]
          }
          return [
            <Menu.SubMenu key={label} title={item.label} popupClassName={`${prefixCls}__sub_menu`}>
              {renderMenuItem(children)}
            </Menu.SubMenu>,
            DividerComp,
          ]
        })
      }
      return () => {
        const { items } = props
        return (
          <div ref={wrapRef} class="content-menu">
            <Menu
              v-model_selectedKeys={selectedKeys}
              inlineIndent={12}
              mode="vertical"
              v-show={state.show}
              style={unref(getStyle)}
            >
              {renderMenuItem(items as ContextMenuItem[])}
            </Menu>
          </div>
        )
      }
    },
  })
</script>
<style lang="scss">
  .content-menu {
    .ant-menu {
      position: fixed;
      top: 0;
      left: 0;
      z-index: 300;
      display: block;
      width: 156px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;
      user-select: none;

      .ant-menu-item {
        height: 36px;
        margin-bottom: 0 !important;
        line-height: 36px;

        &:hover:not(.ant-menu-item-disabled) {
          color: inherit;
          cursor: pointer;
          background: fade-in(#e6f7ff, 0.5%);
        }
        &:hover {
          background-color: rgba(0, 0, 0, 0.12);
        }
      }
    }
    .ant-divider {
      margin: 0 0;
      &:last-of-type {
        height: 0;
      }
    }
    &__sub_menu {
      .ant-menu-item {
        margin-bottom: 4px !important;
      }
      .ant-divider {
        margin: 0 0;
        &:last-of-type {
          height: 0;
        }
      }
    }
  }
</style>
